package com.coocaa.typhoon.api.third.volcengine.util;

import cn.hutool.core.util.StrUtil;
import com.coocaa.cirrus.common.base.exception.BusinessException;
import com.coocaa.cirrus.common.base.util.DateUtil;
import com.coocaa.typhoon.api.third.volcengine.model.VikingDbUserFileEntity;
import com.coocaa.typhoon.api.third.volcengine.model.output.UserFileVO;
import com.coocaa.typhoon.api.v1.userfile.model.input.GetSearchDataModel;
import com.coocaa.typhoon.api.v1.userfile.util.FileTypeCheckUtil;
import com.volcengine.service.vikingDB.common.DataObject;
import com.volcengine.service.vikingDB.common.SearchParam;
import com.volcengine.service.vikingDB.common.SearchWithMultiModalParam;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author bijiahao
 * @date : 2025/9/19 17:51
 * @description
 */
@Slf4j
@UtilityClass
public class VikingDbConvert {

    public static SearchWithMultiModalParam getSearchWithMultiModalParam(GetSearchDataModel dataModel, String tosLink) {
        try {
            SearchWithMultiModalParam param = new SearchWithMultiModalParam();
            if (StringUtils.isNotBlank(dataModel.getText())) {
                param.setText(dataModel.getText());
            }
            if (StringUtils.isNotBlank(tosLink)) {
                //tos://your_bucket/your_object
                // 设置图片输入为存储在指定路径的图片
                param.setImage(tosLink);
            }
            //https://www.volcengine.com/docs/84313/1521858
            param.setFilter(getFilerMap(dataModel));
            if (null != dataModel.getLimit()) {
                param.setLimit(dataModel.getLimit());
            }
            return param.build();
        } catch (Exception e) {
            log.error("getSearchWithMultiModalParam", e);
            throw new BusinessException("构建查询参数异常");
        }
    }

    public static SearchParam getSearchParam(GetSearchDataModel dataModel) {
        try {
            SearchParam searchParam = new SearchParam();
            Map<String, Object> filter = new HashMap<>();
//            filterByUserId(filter, dataModel.getUserId());
            Map<String, Object> filterMap = getFilerMap(dataModel);
            searchParam.setFilter(filterMap);
            searchParam.setOutputFields(VikingDbConvert.getColumnNames(VikingDbUserFileEntity.class));
            if (null != dataModel.getLimit()) {
                searchParam.setLimit(dataModel.getLimit());
            }
            return searchParam.build();
        } catch (Exception e) {
            log.error("getSearchParam", e);
            throw new BusinessException("构建查询参数异常");
        }
    }

    public static void filterByUserId(Map<String, Object> filter, String userId) {
        filter.put("op", "must");
        filter.put("field", "user_id");
        filter.put("conds", new String[]{userId});
    }

    /**
     * 标量过滤
     *
     * @param dataModel
     * @return
     */
    public static Map<String, Object> getFilerMap(GetSearchDataModel dataModel) {
        Map<String, Object> filter = new HashMap<>();
        AtomicBoolean isFilter = new AtomicBoolean(false);
        List<Map<String, Object>> filterConditions = new ArrayList<>();
        if (StringUtils.isNotBlank(dataModel.getUserId())) {
            isFilter.set(true);
            filter.put("op", "and");
            Map<String, Object> userFilter = new HashMap<>();
            userFilter.put("op", "must");
            userFilter.put("field", "user_id");
            userFilter.put("conds", new String[]{dataModel.getUserId()});
            filterConditions.add(userFilter);
        }
        if (FileTypeCheckUtil.isSupportFileTypeQuery(dataModel.getFileType())) {
            isFilter.set(true);
            Map<String, Object> userFilter = new HashMap<>();
            userFilter.put("op", "must");
            userFilter.put("field", "file_type");
            userFilter.put("conds", FileTypeCheckUtil.getFileTypeForQuery(dataModel.getFileType()));
            filterConditions.add(userFilter);
        }
        handleFilterByShootTime(dataModel, isFilter, filterConditions);
//        if (isTimeCanFilter(dataModel.getUploadStartTime()) && isTimeCanFilter(dataModel.getUploadEndTime())) {
//            isFilter = true;
//            Map<String, Object> userFilter = new HashMap<>();
//            userFilter.put("op", "range");
//            userFilter.put("field", "upload_time");
//            userFilter.put("gt", dataModel.getUploadStartTime());
//            userFilter.put("lt", dataModel.getUploadEndTime());
//
//            filterConditions.add(userFilter);
//        } else if (isTimeCanFilter(dataModel.getUploadStartTime()) && !isTimeCanFilter(dataModel.getUploadEndTime())) {
//            isFilter = true;
//            Map<String, Object> userFilter = new HashMap<>();
//            userFilter.put("op", "range");
//            userFilter.put("field", "upload_time");
//            userFilter.put("gt", dataModel.getUploadStartTime());
//
//            filterConditions.add(userFilter);
//        } else if (!isTimeCanFilter(dataModel.getUploadStartTime()) && isTimeCanFilter(dataModel.getUploadEndTime())) {
//            isFilter = true;
//            Map<String, Object> userFilter = new HashMap<>();
//            userFilter.put("op", "range");
//            userFilter.put("field", "upload_time");
//            userFilter.put("lt", dataModel.getUploadEndTime());
//
//            filterConditions.add(userFilter);
//        }
        if (!isFilter.get()) {
            return null;
        }
        filter.put("conds", filterConditions);
        return filter;
    }

    private static void handleFilterByShootTime(GetSearchDataModel dataModel, AtomicBoolean isFilter, List<Map<String, Object>> filterConditions) {
        long startTime = DateUtil.toTimestamp(dataModel.getStartDate());
        long endTime = DateUtil.toTimestamp(dataModel.getEndDate());
        if (isTimeCanFilter(startTime) && isTimeCanFilter(endTime)) {
            isFilter.set(true);
            Map<String, Object> userFilter = new HashMap<>();
            userFilter.put("op", "range");
            userFilter.put("field", "shoot_time");
            userFilter.put("gt", startTime);
            userFilter.put("lt", endTime);
            filterConditions.add(userFilter);
        } else if (isTimeCanFilter(startTime) && !isTimeCanFilter(endTime)) {
            isFilter.set(true);
            Map<String, Object> userFilter = new HashMap<>();
            userFilter.put("op", "range");
            userFilter.put("field", "shoot_time");
            userFilter.put("gt", startTime);
            filterConditions.add(userFilter);
        } else if (!isTimeCanFilter(startTime) && isTimeCanFilter(endTime)) {
            isFilter.set(true);
            Map<String, Object> userFilter = new HashMap<>();
            userFilter.put("op", "range");
            userFilter.put("field", "shoot_time");
            userFilter.put("lt", endTime);
            filterConditions.add(userFilter);
        }
    }

    public static boolean isTimeCanFilter(Long time) {
        return time != null && time > 0;
    }

    public static List<String> getColumnNames(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        List<String> res = Arrays.stream(fields).map(field -> StrUtil.toUnderlineCase(field.getName())).collect(Collectors.toList());
        return res;
    }

    public static List<DataObject> convertDataObjectList(List<VikingDbUserFileEntity> entityList) {
        List<DataObject> res = entityList.stream().map(VikingDbConvert::convertDataObject).filter(Objects::nonNull).collect(Collectors.toList());
        return res;
    }

    public static List<UserFileVO> convertUserFileVOList(List<DataObject> dataObjectList) {
        List<UserFileVO> res = new ArrayList<>();
        dataObjectList.forEach(dataObject -> {
            Double score = dataObject.getScore();
            UserFileVO userFileVO = VikingDbConvert.convertMapToEntity(dataObject.getFields(), UserFileVO.class);
            if (null != userFileVO) {
                userFileVO.setScore(score);
                res.add(userFileVO);
            }
        });
        return res;
    }


    public static DataObject convertDataObject(VikingDbUserFileEntity entity) {
        try {
            HashMap<String, Object> fields = convertEntityToMap(entity);
            DataObject dataObject = new DataObject()
                    .setFields(fields)
                    .build();
            return dataObject;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    public static <T> T convertMapToEntity(Map<String, Object> map, Class<T> clazz) {
        try {
            if (MapUtils.isEmpty(map)) {
                return null;
            }
            T entity = clazz.newInstance();
            Field[] fields = clazz.getDeclaredFields();
            // 遍历Map并设置对象的字段
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String fieldName = StrUtil.toCamelCase(entry.getKey());
                Field field = Arrays.stream(fields).filter(f -> f.getName().equals(fieldName)).findFirst().orElse(null);
                // 使用反射设置字段值
                if (null != field) {
                    field.setAccessible(true);
                    // 这里可能需要额外的类型检查和转换
                    field.set(entity, entry.getValue());
                }
            }
            return entity;
        } catch (Exception e) {
            log.error("convertMapToEntity error", e);
            return null;
        }
    }

    public static HashMap<String, Object> convertEntityToMap(Object entity) {
        HashMap<String, Object> res = new HashMap<>();
        try {
            Field[] fields = entity.getClass().getDeclaredFields();
            for (Field field : fields) {
                String key = StrUtil.toUnderlineCase(field.getName());
                field.setAccessible(true);
                res.put(key, field.get(entity));
            }
            return res;
        } catch (IllegalAccessException e) {
            log.error("convertEntityToMap error", e);
            return res;
        }
    }

}
